package cn.tp.ksoft.civil_driver.view.widget;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.support.v4.util.Pools;
import android.support.v4.view.ViewCompat;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.PopupWindow;
import android.widget.TextView;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;

import cn.tp.ksoft.civil_driver.R;

/**
 * Created by zhusong on 16/4/28.
 */
public class IndexView extends LinearLayout {

    private static final int DEFAULT_PADDING = 5;//DPS
    private static final int DEFAULT_POPUP_WIDTH = 35;//DPS
    public static final String[] DEFAULT_INDEX = { "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K",
            "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X",
            "Y", "Z", "#" };
    private String[] arrays;
    private int mMaskColor;
    private int mTextAppearance;
    private boolean mFillView;
    private int mPadding;

    private Pools.Pool<IndexItem> mItemsPool = new Pools.SimplePool<>(16);
    private Pools.Pool<TextView> mViewsPool = new Pools.SynchronizedPool<>(12);
    private ArrayList<IndexItem> mItems = new ArrayList<>(16);

    private ArrayList<Integer> mItemsPositionList = new ArrayList<>();
    private Integer[] mItemsPosition;

    private OnIndexClickListener mIndexListener;

    private PopupWindow mPopupWin;
    private TextView mPopupTextView;
    private int mPopupWidth;

    public IndexView(Context context) {
        this(context, null);
    }

    public IndexView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public IndexView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);

        setOrientation(VERTICAL);
        TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.IndexView);
        int arrayResId = ta.getResourceId(R.styleable.IndexView_arrays, -1);
        if (arrayResId > 0) {
            arrays = getResources().getStringArray(arrayResId);
        } else {
            arrays = DEFAULT_INDEX;
        }
        mFillView = ta.getBoolean(R.styleable.IndexView_fillView, true);
        mMaskColor = ta.getColor(R.styleable.IndexView_maskColor, -1);
        mTextAppearance = ta.getResourceId(R.styleable.IndexView_android_textAppearance, -1);
        DisplayMetrics dm = getResources().getDisplayMetrics();
        final int padding = Math.round(DEFAULT_PADDING * dm.density);
        mPadding = ta.getDimensionPixelSize(R.styleable.IndexView_android_padding, padding);

        int popupTextViewResId = ta.getResourceId(R.styleable.IndexView_popupTextView, -1);
        if (popupTextViewResId > 0) {
            mPopupTextView = (TextView) LayoutInflater.from(context).inflate(popupTextViewResId, null);
        } else {
            mPopupTextView = new TextView(context);
            mPopupTextView.setTextAppearance(context, android.R.style.TextAppearance_DeviceDefault_Large);
            mPopupTextView.setBackgroundColor(Color.parseColor("#3f666666"));
            mPopupTextView.setGravity(Gravity.CENTER);
        }
        ViewCompat.setPaddingRelative(mPopupTextView, padding, padding, padding, padding);
        int popupWidth = Math.round(DEFAULT_POPUP_WIDTH * dm.density);
        mPopupWidth = ta.getDimensionPixelSize(R.styleable.IndexView_popupWidth, popupWidth);
        ta.recycle();

        updateArrays();
    }

    private void updateArrays() {
        removeAllIndex();
        if (null == arrays) {
            return;
        }

        for (int i = 0; i < arrays.length; i++) {
            String text = arrays[i];
            addViewInternal(text);
        }
    }

    public void removeAllIndex() {
        for (int i = getChildCount()-1; i >=0; i--) {
            removeIndexAt(i);
        }

        for (Iterator<IndexItem> iterator = mItems.iterator(); iterator.hasNext();) {
            IndexItem item = iterator.next();
            iterator.remove();
            item.reset();
            mItemsPool.release(item);
        }
    }

    public void setOnIndexClickListener(OnIndexClickListener listener) {
        this.mIndexListener = listener;
    }

    private void removeIndexAt(int position) {
        TextView textView = (TextView) getChildAt(position);
        removeViewAt(position);
        if (textView != null) {
            textView.setText(null);
            textView.setOnClickListener(null);
            mViewsPool.release(textView);
        }
        requestLayout();
    }
    private void addViewInternal(CharSequence text){
        TextView view = mViewsPool.acquire();
        if (null == view) {
            view = new TextView(getContext());
            if (mTextAppearance > 0) {
                view.setTextAppearance(getContext(), mTextAppearance);
            }
            view.setGravity(Gravity.CENTER);
        }
        LayoutParams lp = generateDefaultLayoutParams();
        int padding = mFillView ? 0 : mPadding;
        if (getOrientation() == VERTICAL) {
            ViewCompat.setPaddingRelative(view, 0, padding, 0, padding);
            lp.width = LayoutParams.MATCH_PARENT;
        } else {
            ViewCompat.setPaddingRelative(view, padding, 0, padding, 0);
            lp.height = LayoutParams.MATCH_PARENT;
        }
        if (mFillView) {
            lp.weight = 1;
        }
        view.setLayoutParams(lp);
        view.setText(text);
        addView(view);
        IndexItem item = new IndexItem();
        item.mView = view;
        item.mSectionName = text.toString();
        item.section = mItems.size();
        mItems.add(item);

        for (int i = 0; i < mItems.size(); i++) {
            mItems.get(i).setSection(i);
        }
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        super.onLayout(changed, l, t, r, b);
        mItemsPositionList.clear();
        if (getOrientation() == VERTICAL) {
            for (int i = 0; i < getChildCount(); i++) {
                View child = getChildAt(i);
                mItemsPositionList.add(child.getTop());
            }
        } else {
            for (int i = 0; i < getChildCount(); i++) {
                View child = getChildAt(i);
                mItemsPositionList.add(child.getLeft());
            }
        }

        mItemsPosition = new Integer[getChildCount()];
        mItemsPositionList.toArray(mItemsPosition);
    }

    private int mCurrentIndex = -1;
    private boolean mShowMask;
    @Override
    protected void dispatchDraw(Canvas canvas) {
        super.dispatchDraw(canvas);
        if (mShowMask) {
            canvas.drawColor(mMaskColor);
        }
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent event) {

        int action = event.getAction();
        if (action == MotionEvent.ACTION_DOWN) {
            mShowMask = true;
        } else if (action == MotionEvent.ACTION_CANCEL
                || action == MotionEvent.ACTION_UP) {
            mShowMask = false;
            if (null != mPopupWin && mPopupWin.isShowing()) {
                mPopupWin.dismiss();
            }
            mCurrentIndex = -1;
            return true;
        }
        int position = Math.round(getOrientation() == VERTICAL ? event.getY() : event.getX());
        int index = Arrays.binarySearch(mItemsPosition, position);
        if (index < 0) {
            index = ~index - 1;
        }

        if (index >= 0 && mCurrentIndex != index) {
            IndexItem item = mItems.get(index);

            if (null != mIndexListener) {
                mIndexListener.onIndexClick(item);
            }
            mCurrentIndex = index;

            if (null == mPopupWin) {
                mPopupWin = new PopupWindow(mPopupTextView);
                mPopupWin.setWidth(mPopupWidth);
                mPopupWin.setHeight(mPopupWidth);
            }
            mPopupTextView.setText(arrays[index]);
            if (mPopupWin.isShowing()) {
                mPopupWin.update();
            } else {
                mPopupWin.showAtLocation(getRootView(),
                        Gravity.CENTER, 0, 0);
            }
        }
        return true;
    }

    @Override
    public void addView(View child) {
        if (!(child instanceof TextView)) {
            throw new IllegalArgumentException("IndexView Only can add TextView");
        }
        super.addView(child);
    }

    @Override
    public void addView(View child, int index) {
        if (!(child instanceof TextView)) {
            throw new IllegalArgumentException("IndexView Only can add TextView");
        }
        super.addView(child, index);
    }

    @Override
    public void addView(View child, ViewGroup.LayoutParams params) {
        if (!(child instanceof TextView)) {
            throw new IllegalArgumentException("IndexView Only can add TextView");
        }
        super.addView(child, params);
    }

    @Override
    public void addView(View child, int width, int height) {
        if (!(child instanceof TextView)) {
            throw new IllegalArgumentException("IndexView Only can add TextView");
        }
        super.addView(child, width, height);
    }

    @Override
    public void addView(View child, int index, ViewGroup.LayoutParams params) {
        if (!(child instanceof TextView)) {
            throw new IllegalArgumentException("IndexView Only can add TextView");
        }
        super.addView(child, index, params);
    }

    public interface OnIndexClickListener {
        public void onIndexClick(IndexItem item);
    }

    public static class IndexItem {

        private static final int INVALID_SECTION = -1;
        private Object mTag;
        private TextView mView;
        private int section = INVALID_SECTION;
        private String mSectionName;
        public IndexItem setTag(Object tag) {
            this.mTag = tag;
            return this;
        }

        public IndexItem setView(TextView view) {
            mView = view;
            return this;
        }
        public IndexItem setSection(int section) {
            this.section = section;
            return this;
        }

        public void setSectionName(String sectionName) {
            this.mSectionName = sectionName;
        }

        public Object getTag() {
            return mTag;
        }

        public int getSection() {
            return section;
        }

        public String getSectionName() {
            return mSectionName;
        }

        public void reset() {
            mTag = null;
            mView = null;
            section = INVALID_SECTION;
        }
    }
}
